package com.sojson.util.httpclient;

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.alibaba.fastjson.JSONObject;
import com.sojson.config.exception.TransException;
import com.sojson.constant.Constant;
import com.sojson.util.StringUtil;
import com.sojson.util.file.FileUtil;
import com.sojson.util.httpclient.impl.HttpClientUtilImpl;
import com.sojson.util.properties.PropertiesUtil;
import com.sojson.util.servlet.ServletUtil;
import com.sojson.util.text.Convert;

/**
 * HttpClient工具类
 * 
 * @author liu
 * @date 2020-11-02
 */
public class HttpClientUtil {

    public static final HttpClientUtilInterface httpClientUtilsInterface = HttpClientUtilImpl.getInstances();
    /** 编码格式,发送编码格式,不设置为UTF-8 */
    public static String encoding =
        Convert.toStr(Constant.PROPERTIES.getProperty("so.httpclient.encoding"), Constant.DEFAULT_ENCODING);
    /** 设置连接超时时间,单位毫秒,不设置为6000 */
    public static int connectTimeout = Convert.toInt(
        PropertiesUtil.getNumberFormat(Constant.PROPERTIES.getProperty("so.httpclient.connectTimeout")), 1000 * 6);
    /** 请求获取数据的超时时间(即响应时间),单位毫秒,不设置为10000 */
    public static int socketTimeout = Convert.toInt(
        PropertiesUtil.getNumberFormat(Constant.PROPERTIES.getProperty("so.httpclient.socketTimeout")), 1000 * 10);

    /**
     * 重定向
     * 
     * @param url 地址
     * @throws IOException
     */
    public static void redirect(String url) throws IOException {
        ServletUtil.getHttpServletResponse().sendRedirect(url);
    }

    /**
     * 重定向
     * 
     * @param url 地址
     * @param params 参数(Json数据格式)
     * @throws IOException
     */
    public static void redirectByParam(String url, String params) throws IOException {
        url = setParam(url, params);

        ServletUtil.getHttpServletResponse().sendRedirect(url);
    }

    /**
     * 重定向
     * 
     * @param url 地址
     * @param params 参数
     * @throws IOException
     */
    public static void redirectByParam(String url, Map<String, String> params) throws IOException {
        url = setParam(url, params);

        ServletUtil.getHttpServletResponse().sendRedirect(url);
    }

    /**
     * 重定向
     * 
     * @param url 地址
     * @param params 请求头(Json数据格式)
     * @throws IOException
     */
    public static void redirectByHeader(String url, String headers) throws IOException {
        HttpServletResponse response = ServletUtil.getHttpServletResponse();

        setHeader(response, headers);

        response.sendRedirect(url);
    }

    /**
     * 重定向
     * 
     * @param url 地址
     * @param params 请求头
     * @throws IOException
     */
    public static void redirectByHeader(String url, Map<String, String> headers) throws IOException {
        HttpServletResponse response = ServletUtil.getHttpServletResponse();

        setHeader(response, headers);

        response.sendRedirect(url);
    }

    /**
     * 重定向
     * 
     * @param url 地址
     * @param headers 请求头(Json数据格式)
     * @param params 参数(Json数据格式)
     * @throws IOException
     */
    public static void redirect(String url, String headers, String params) throws IOException {
        HttpServletResponse response = ServletUtil.getHttpServletResponse();

        setHeader(response, headers);

        url = setParam(url, params);

        response.sendRedirect(url);
    }

    /**
     * 重定向
     * 
     * @param url 地址
     * @param headers 请求头
     * @param params 参数(Json数据格式)
     * @throws IOException
     */
    public static void redirect(String url, Map<String, String> headers, String params) throws IOException {
        HttpServletResponse response = ServletUtil.getHttpServletResponse();

        setHeader(response, headers);

        url = setParam(url, params);

        response.sendRedirect(url);
    }

    /**
     * 重定向
     * 
     * @param url 地址
     * @param headers 请求头(Json数据格式)
     * @param params 参数
     * @throws IOException
     */
    public static void redirect(String url, String headers, Map<String, String> params) throws IOException {
        HttpServletResponse response = ServletUtil.getHttpServletResponse();

        setHeader(response, headers);

        url = setParam(url, params);

        response.sendRedirect(url);
    }

    /**
     * 重定向
     * 
     * @param url 地址
     * @param headers 请求头
     * @param params 参数
     * @throws IOException
     */
    public static void redirect(String url, Map<String, String> headers, Map<String, String> params)
        throws IOException {
        HttpServletResponse response = ServletUtil.getHttpServletResponse();

        setHeader(response, headers);

        url = setParam(url, params);

        response.sendRedirect(url);
    }

    /**
     * 给地址设置参数
     * 
     * @param url 地址
     * @param params 参数(Json数据格式)
     * @return
     */
    private static String setParam(String url, String params) {
        if (StringUtil.isNotBlankObject(params)) {
            JSONObject parseObject = JSONObject.parseObject(params);
            Set<Entry<String, Object>> entrySet = parseObject.entrySet();
            StringBuilder stringBuilder = new StringBuilder(url);
            for (Entry<String, Object> entry : entrySet) {
                stringBuilder.append(entry.getKey()).append("=").append(entry.getValue().toString()).append("&");
            }

            if (parseObject.size() > 1) {
                url = stringBuilder.substring(0, stringBuilder.length() - 1);
            } else {
                url = stringBuilder.toString();
            }
        }

        return url;
    }

    /**
     * 给地址设置参数
     * 
     * @param url 地址
     * @param params 参数
     * @return
     */
    private static String setParam(String url, Map<String, String> params) {
        if (StringUtil.isNotBlankObject(params)) {
            Set<Entry<String, String>> entrySet = params.entrySet();
            StringBuilder stringBuilder = new StringBuilder(url);
            for (Entry<String, String> entry : entrySet) {
                stringBuilder.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
            }

            if (params.size() > 1) {
                url = stringBuilder.substring(0, stringBuilder.length() - 1);
            } else {
                url = stringBuilder.toString();
            }
        }

        return url;
    }

    /**
     * 给地址设置请求头
     * 
     * @param response 
     * @param headers 请求头(Json数据格式)
     * @return
     */
    private static void setHeader(HttpServletResponse response, String headers) {
        if (StringUtil.isNotBlankObject(headers)) {
            JSONObject parseObject = JSONObject.parseObject(headers);
            Set<Entry<String, Object>> entrySet = parseObject.entrySet();
            for (Entry<String, Object> entry : entrySet) {
                response.setHeader(entry.getKey(), entry.getValue().toString());
            }
        }
    }

    /**
     * 给地址设置请求头
     * 
     * @param response 
     * @param headers 请求头
     * @return
     */
    private static void setHeader(HttpServletResponse response, Map<String, String> headers) {
        if (StringUtil.isNotBlankObject(headers)) {
            Set<Entry<String, String>> entrySet = headers.entrySet();
            for (Entry<String, String> entry : entrySet) {
                response.setHeader(entry.getKey(), entry.getValue());
            }
        }
    }

    /**
     * 请求转发
     * 
     * @param url 地址
     * @throws Exception
     */
    public static void request(String url) throws Exception {
        HttpServletRequest request = ServletUtil.getHttpServletRequest();
        HttpServletResponse response = ServletUtil.getHttpServletResponse();

        request.getRequestDispatcher(url).forward(request, response);
    }

    /**
     * 请求转发
     * 
     * @param url 地址
     * @param params 参数(Json数据格式)
     * @throws Exception
     */
    public static void request(String url, String params) throws Exception {
        HttpServletRequest request = ServletUtil.getHttpServletRequest();
        HttpServletResponse response = ServletUtil.getHttpServletResponse();

        setParam(request, params);

        request.getRequestDispatcher(url).forward(request, response);
    }

    /**
     * 请求转发
     * 
     * @param url 地址
     * @param params 参数
     * @throws Exception
     */
    public static void request(String url, Map<String, String> params) throws Exception {
        HttpServletRequest request = ServletUtil.getHttpServletRequest();
        HttpServletResponse response = ServletUtil.getHttpServletResponse();

        setParam(request, params);

        request.getRequestDispatcher(url).forward(request, response);
    }

    /**
     * 给地址设置参数
     * 
     * @param request 
     * @param params 参数(Json数据格式)
     * @return
     */
    private static void setParam(HttpServletRequest request, String params) {
        if (StringUtil.isNotBlankObject(params)) {
            JSONObject parseObject = JSONObject.parseObject(params);
            Set<Entry<String, Object>> entrySet = parseObject.entrySet();
            for (Entry<String, Object> entry : entrySet) {
                request.setAttribute(entry.getKey(), entry.getValue().toString());
            }
        }
    }

    /**
     * 给地址设置参数
     * 
     * @param request 
     * @param params 参数
     * @return
     */
    private static void setParam(HttpServletRequest request, Map<String, String> params) {
        if (StringUtil.isNotBlankObject(params)) {
            Set<Entry<String, String>> entrySet = params.entrySet();
            for (Entry<String, String> entry : entrySet) {
                request.setAttribute(entry.getKey(), entry.getValue());
            }
        }
    }

    /**
     * 通过路径获取输入流
     * 
     * @param url 地址
     * @throws IOException
     */
    public static InputStream getInputStream(String url) throws IOException {
        // 获取连接
        HttpURLConnection conn = (HttpURLConnection)new URL(getUrl(url)).openConnection();

        // 初始化连接
        initHttpURLConnection(conn);

        return conn.getInputStream();
    }

    /**
     * 将Url中的中文字符转码
     * 
     * @param url
     * @return
     */
    private static String getUrl(String url) {
        char[] chars = url.toCharArray();
        StringBuilder utf8Url = new StringBuilder();
        final int charCount = chars.length;
        for (int i = 0; i < charCount; i++) {
            byte[] bytes = ("" + chars[i]).getBytes();
            if (bytes.length == 1) {
                utf8Url.append(chars[i]);
            } else {
                try {
                    utf8Url.append(encode(String.valueOf(chars[i])));
                } catch (Exception e) {
                    throw new TransException(e.getMessage());
                }
            }
        }
        return utf8Url.toString();
    }

    /**
     * 通过路径获取字节数组
     * 
     * @param url 地址
     * @throws IOException
     */
    public static byte[] getBytes(String url) throws IOException {
        // 获取输入流
        InputStream inputStream = getInputStream(url);

        return inputStreamToByte(inputStream);
    }

    /**
     * 将InputStream转为byte[]
     * 
     * @param inputStream
     * @return
     * @throws IOException
     */
    private static byte[] inputStreamToByte(InputStream inputStream) throws IOException {
        return FileUtil.inputStreamToByte(inputStream);
    }

    /**
     * 重定向
     * 
     * @param url 地址
     * @throws IOException
     */
    public static void initHttpURLConnection(HttpURLConnection conn) throws IOException {
        // 设置超时时间
        conn.setConnectTimeout(3 * 1000);
        // 防止屏蔽程序抓取而返回403错误
        conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
    }

    /**
     * 编码字符串
     * 
     * @param str
     * @return
     * @throws IOException
     */
    private static String encode(String str) throws IOException {
        return StringUtil.encode(str);
    }

    /**
     * 发送get请求
     * 
     * @param url 请求地址
     * @return
     * @throws Exception 
     */
    public static String doGet(String url) throws Exception {
        return httpClientUtilsInterface.doGet(url);
    }

    /**
     * 发送get请求
     * 
     * @param url 请求地址
     * @param headers 请求头(Json数据格式)
     * @return
     * @throws Exception 
     */
    public static String doGetByHeader(String url, String headers) throws Exception {
        return httpClientUtilsInterface.doGetByHeader(url, headers);
    }

    /**
     * 发送get请求
     * 
     * @param url 请求地址
     * @param headers 请求头
     * @return
     * @throws Exception 
     */
    public static String doGetByHeader(String url, Map<String, String> headers) throws Exception {
        return httpClientUtilsInterface.doGetByHeader(url, headers);
    }

    /**
     * 发送get请求
     * 
     * @param url 请求地址
     * @param params 参数(Json数据格式)
     * @return
     * @throws Exception 
     */
    public static String doGetByParam(String url, String params) throws Exception {
        return httpClientUtilsInterface.doGetByParam(url, params);
    }

    /**
     * 发送get请求
     * 
     * @param url 请求地址
     * @param params 参数
     * @return
     * @throws Exception 
     */
    public static String doGetByParam(String url, Map<String, String> params) throws Exception {
        return httpClientUtilsInterface.doGetByParam(url, params);
    }

    /**
     * 发送get请求
     * 
     * @param url 请求地址
     * @param headers 请求头(Json数据格式)
     * @param params 参数(Json数据格式)
     * @return
     * @throws Exception 
     */
    public static String doGet(String url, String headers, String params) throws Exception {
        return httpClientUtilsInterface.doGet(url, headers, params);
    }

    /**
     * 发送get请求
     * 
     * @param url 请求地址
     * @param headers 请求头
     * @param params 参数(Json数据格式)
     * @return
     * @throws Exception 
     */
    public static String doGet(String url, Map<String, String> headers, String params) throws Exception {
        return httpClientUtilsInterface.doGet(url, headers, params);
    }

    /**
     * 发送get请求
     * 
     * @param url 请求地址
     * @param headers 请求头(Json数据格式)
     * @param params 参数
     * @return
     * @throws Exception 
     */
    public static String doGet(String url, String headers, Map<String, String> params) throws Exception {
        return httpClientUtilsInterface.doGet(url, headers, params);
    }

    /**
     * 发送get请求
     * 
     * @param url 请求地址
     * @param headers 请求头
     * @param params 参数
     * @return
     * @throws Exception 
     */
    public static String doGet(String url, Map<String, String> headers, Map<String, String> params) throws Exception {
        return httpClientUtilsInterface.doGet(url, headers, params);
    }

    /**
     * 发送post请求
     * 
     * @param url 请求地址
     * @return
     * @throws IOException 
     */
    public static String doPost(String url) throws IOException {
        return httpClientUtilsInterface.doPost(url);
    }

    /**
     * 发送post请求
     * 
     * @param url 请求地址
     * @param headers 请求头(Json数据格式)
     * @return
     * @throws IOException 
     */
    public static String doPostByHeader(String url, String headers) throws IOException {
        return httpClientUtilsInterface.doPostByHeader(url, headers);
    }

    /**
     * 发送post请求
     * 
     * @param url 请求地址
     * @param headers 请求头
     * @return
     * @throws IOException 
     */
    public static String doPostByHeader(String url, Map<String, String> headers) throws IOException {
        return httpClientUtilsInterface.doPostByHeader(url, headers);
    }

    /**
     * 发送post请求
     * 
     * @param url 请求地址
     * @param params 参数(Json数据格式)
     * @return
     * @throws IOException 
     */
    public static String doPostByParam(String url, String params) throws IOException {
        return httpClientUtilsInterface.doPostByParam(url, params);
    }

    /**
     * 发送post请求
     * 
     * @param url 请求地址
     * @param params 参数
     * @return
     * @throws IOException 
     */
    public static String doPostByParam(String url, Map<String, String> params) throws IOException {
        return httpClientUtilsInterface.doPostByParam(url, params);
    }

    /**
     * 发送post请求
     * 
     * @param url 请求地址
     * @param headers 请求头(Json数据格式)
     * @param params 参数(Json数据格式)
     * @return
     * @throws IOException 
     */
    public static String doPost(String url, String headers, String params) throws IOException {
        return httpClientUtilsInterface.doPost(url, headers, params);
    }

    /**
     * 发送post请求
     * 
     * @param url 请求地址
     * @param headers 请求头
     * @param params 参数(Json数据格式)
     * @return
     * @throws IOException 
     */
    public static String doPost(String url, Map<String, String> headers, String params) throws IOException {
        return httpClientUtilsInterface.doPost(url, headers, params);
    }

    /**
     * 发送post请求
     * 
     * @param url 请求地址
     * @param headers 请求头(Json数据格式)
     * @param params 参数
     * @return
     * @throws IOException 
     */
    public static String doPost(String url, String headers, Map<String, String> params) throws IOException {
        return httpClientUtilsInterface.doPost(url, headers, params);
    }

    /**
     * 发送post请求
     * 
     * @param url 请求地址
     * @param headers 请求头
     * @param params 参数
     * @return
     * @throws IOException 
     */
    public static String doPost(String url, Map<String, String> headers, Map<String, String> params)
        throws IOException {
        return httpClientUtilsInterface.doPost(url, headers, params);
    }

    /**
     * 发送put请求
     * 
     * @param url 请求地址
     * @param params 参数
     * @return
     * @throws IOException 
     */
    public static String doPut(String url) throws IOException {
        return httpClientUtilsInterface.doPut(url);
    }

    /**
     * 发送put请求
     * 
     * @param url 请求地址
     * @param params 参数
     * @return
     * @throws IOException 
     */
    public static String doPut(String url, Map<String, String> params) throws IOException {
        return httpClientUtilsInterface.doPut(url, params);
    }

    /**
     * 发送delete请求
     * 
     * @param url 请求地址
     * @param params 参数
     * @return
     * @throws IOException 
     */
    public static String doDelete(String url) throws IOException {
        return httpClientUtilsInterface.doDelete(url);
    }

    /**
     * 发送delete请求
     * 
     * @param url 请求地址
     * @param params 参数
     * @return
     * @throws IOException 
     */
    public static String doDelete(String url, Map<String, String> params) throws IOException {
        return httpClientUtilsInterface.doDelete(url, params);
    }

    /**
     * 发送get请求
     * 
     * @param url 请求地址
     * @return
     * @throws Exception 
     */
    public static byte[] doGetByte(String url) throws Exception {
        return httpClientUtilsInterface.doGetByte(url);
    }

    /**
     * 发送get请求
     * 
     * @param url 请求地址
     * @param headers 请求头(Json数据格式)
     * @return
     * @throws Exception 
     */
    public static byte[] doGetByteByHeader(String url, String headers) throws Exception {
        return httpClientUtilsInterface.doGetByteByHeader(url, headers);
    }

    /**
     * 发送get请求
     * 
     * @param url 请求地址
     * @param headers 请求头
     * @return
     * @throws Exception 
     */
    public static byte[] doGetByteByHeader(String url, Map<String, String> headers) throws Exception {
        return httpClientUtilsInterface.doGetByteByHeader(url, headers);
    }

    /**
     * 发送get请求
     * 
     * @param url 请求地址
     * @param params 参数(Json数据格式)
     * @return
     * @throws Exception 
     */
    public static byte[] doGetByteByParam(String url, String params) throws Exception {
        return httpClientUtilsInterface.doGetByteByParam(url, params);
    }

    /**
     * 发送get请求
     * 
     * @param url 请求地址
     * @param params 参数
     * @return
     * @throws Exception 
     */
    public static byte[] doGetByteByParam(String url, Map<String, String> params) throws Exception {
        return httpClientUtilsInterface.doGetByteByParam(url, params);
    }

    /**
     * 发送get请求
     * 
     * @param url 请求地址
     * @param headers 请求头(Json数据格式)
     * @param params 参数(Json数据格式)
     * @return
     * @throws Exception 
     */
    public static byte[] doGetByte(String url, String headers, String params) throws Exception {
        return httpClientUtilsInterface.doGetByte(url, headers, params);
    }

    /**
     * 发送get请求
     * 
     * @param url 请求地址
     * @param headers 请求头
     * @param params 参数(Json数据格式)
     * @return
     * @throws Exception 
     */
    public static byte[] doGetByte(String url, Map<String, String> headers, String params) throws Exception {
        return httpClientUtilsInterface.doGetByte(url, headers, params);
    }

    /**
     * 发送get请求
     * 
     * @param url 请求地址
     * @param headers 请求头(Json数据格式)
     * @param params 参数
     * @return
     * @throws Exception 
     */
    public static byte[] doGetByte(String url, String headers, Map<String, String> params) throws Exception {
        return httpClientUtilsInterface.doGetByte(url, headers, params);
    }

    /**
     * 发送get请求
     * 
     * @param url 请求地址
     * @param headers 请求头
     * @param params 参数
     * @return
     * @throws Exception 
     */
    public static byte[] doGetByte(String url, Map<String, String> headers, Map<String, String> params)
        throws Exception {
        return httpClientUtilsInterface.doGetByte(url, headers, params);
    }

    /**
     * 发送post请求
     * 
     * @param url 请求地址
     * @return
     * @throws IOException 
     */
    public static byte[] doPostByte(String url) throws IOException {
        return httpClientUtilsInterface.doPostByte(url);
    }

    /**
     * 发送post请求
     * 
     * @param url 请求地址
     * @param headers 请求头(Json数据格式)
     * @return
     * @throws IOException 
     */
    public static byte[] doPostByteByHeader(String url, String headers) throws IOException {
        return httpClientUtilsInterface.doPostByteByHeader(url, headers);
    }

    /**
     * 发送post请求
     * 
     * @param url 请求地址
     * @param headers 请求头
     * @return
     * @throws IOException 
     */
    public static byte[] doPostByteByHeader(String url, Map<String, String> headers) throws IOException {
        return httpClientUtilsInterface.doPostByteByHeader(url, headers);
    }

    /**
     * 发送post请求
     * 
     * @param url 请求地址
     * @param params 参数(Json数据格式)
     * @return
     * @throws IOException 
     */
    public static byte[] doPostByteByParam(String url, String params) throws IOException {
        return httpClientUtilsInterface.doPostByteByParam(url, params);
    }

    /**
     * 发送post请求
     * 
     * @param url 请求地址
     * @param params 参数
     * @return
     * @throws IOException 
     */
    public static byte[] doPostByteByParam(String url, Map<String, String> params) throws IOException {
        return httpClientUtilsInterface.doPostByteByParam(url, params);
    }

    /**
     * 发送post请求
     * 
     * @param url 请求地址
     * @param headers 请求头(Json数据格式)
     * @param params 参数(Json数据格式)
     * @return
     * @throws IOException 
     */
    public static byte[] doPostByte(String url, String headers, String params) throws IOException {
        return httpClientUtilsInterface.doPostByte(url, headers, params);
    }

    /**
     * 发送post请求
     * 
     * @param url 请求地址
     * @param headers 请求头
     * @param params 参数(Json数据格式)
     * @return
     * @throws IOException 
     */
    public static byte[] doPostByte(String url, Map<String, String> headers, String params) throws IOException {
        return httpClientUtilsInterface.doPostByte(url, headers, params);
    }

    /**
     * 发送post请求
     * 
     * @param url 请求地址
     * @param headers 请求头(Json数据格式)
     * @param params 参数
     * @return
     * @throws IOException 
     */
    public static byte[] doPostByte(String url, String headers, Map<String, String> params) throws IOException {
        return httpClientUtilsInterface.doPostByte(url, headers, params);
    }

    /**
     * 发送post请求
     * 
     * @param url 请求地址
     * @param headers 请求头
     * @param params 参数
     * @return
     * @throws IOException 
     */
    public static byte[] doPostByte(String url, Map<String, String> headers, Map<String, String> params)
        throws IOException {
        return httpClientUtilsInterface.doPostByte(url, headers, params);
    }

    /**
     * 发送put请求
     * 
     * @param url 请求地址
     * @param params 参数
     * @return
     * @throws IOException 
     */
    public static byte[] doPutByte(String url) throws IOException {
        return httpClientUtilsInterface.doPutByte(url);
    }

    /**
     * 发送put请求
     * 
     * @param url 请求地址
     * @param params 参数
     * @return
     * @throws IOException 
     */
    public static byte[] doPutByte(String url, Map<String, String> params) throws IOException {
        return httpClientUtilsInterface.doPutByte(url, params);
    }

    /**
     * 发送delete请求
     * 
     * @param url 请求地址
     * @param params 参数
     * @return
     * @throws IOException 
     */
    public static byte[] doDeleteByte(String url) throws IOException {
        return httpClientUtilsInterface.doDeleteByte(url);
    }

    /**
     * 发送delete请求
     * 
     * @param url 请求地址
     * @param params 参数
     * @return
     * @throws IOException 
     */
    public static byte[] doDeleteByte(String url, Map<String, String> params) throws IOException {
        return httpClientUtilsInterface.doDeleteByte(url, params);
    }

}